
#include <stdio.h>
#include "evaluate.h"
params InitParams;

FILE *fedbg;

int R_legaloffsetTab[RLOFFSET_MAX]  = {-8,-1,1,8};
int B_legaloffsetTab[BLOFFSET_MAX] = {-9,-7,7,9};
int Q_legaloffsetTab[QLOFFSET_MAX] = {-9,-8,-7,-1,1,7,8,9};
int N_legaloffsetTab[NLOFFSET_MAX] = {-17,-15,-10,-6,6,10,15,17};
#ifndef TWOPAWNMOVE
int P_legaloffsetTab0[PLOFFSET_MAX] = {7,8,9};//16};
int P_legaloffsetTab1[PLOFFSET_MAX] = {-9,-8,-7};//-16};
#else
int P_legaloffsetTab0[PLOFFSET_MAX] = {7,8,9,16};
int P_legaloffsetTab1[PLOFFSET_MAX] = {-9,-8,-7,-16};
#endif

int K_legaloffsetTab[KLOFFSET_MAX] = {-9,-8,-7,-1,1,7,8,9};


char pieceNotation[] = {'P','N','B','R','Q','K'};

unsigned int numDynAnalysis;

#if 0
float intrinsicValue[]={
	2, // pawn
	30, // night
	35, // bishop
	42, // rook
	70, // QUEEN
	10000 // KING
};
#else
#if 0
float intrinsicValue[]={
	1, // pawn
	3, // night
	4, // bishop
	6, // rook
	9, // QUEEN
	10 // KING
};
#else
float intrinsicValue[]={
	9, // pawn
	11, // night
	13, // bishop
	15, // rook
	20, // QUEEN
	100 // KING
};
#endif
#endif


void *createPlayer(int id){
	playerObj *p;
	p = (playerObj *)malloc(sizeof(playerObj));
	p->playerid = id;
	return (void *)p;
}

void makePiece(boardState *pbs,int playeridx, int pieceidx, int squareidx, int pieceType)
{
	pbs->board[squareidx] = pieceidx;
	pbs->pieces[pieceidx].isalive = TRUE;
	pbs->pieces[pieceidx].piecetype = pieceType;
	pbs->pieces[pieceidx].playeridx = playeridx;
	pbs->pieces[pieceidx].squareidx = squareidx;
	pbs->pieces[pieceidx].vint = intrinsicValue[pieceType];
	pbs->pieces[pieceidx].vdyn = 0;
	pbs->pieces[pieceidx].vpos = 0;
	pbs->pieces[pieceidx].wint = 1;
	pbs->pieces[pieceidx].wdyn = 5;
	if(pieceType == KING)
		pbs->pieces[pieceidx].wpos = 0;
	else 
		pbs->pieces[pieceidx].wpos = 1;

	pbs->pieces[pieceidx].influence_numsquares = 0;
	memset(pbs->pieces[pieceidx].influence_squarepos, 0, 64*sizeof(int));
	calcTotVal(pbs,pieceidx);

	switch (pieceType)
	{
		case PAWN:
			if(playeridx == 0){
				pbs->pieces[pieceidx].numlegaloffsets = PLOFFSET_MAX;
				pbs->pieces[pieceidx].legaloffsetTab = &P_legaloffsetTab0;
			}else{
				pbs->pieces[pieceidx].numlegaloffsets = PLOFFSET_MAX;
				pbs->pieces[pieceidx].legaloffsetTab = &P_legaloffsetTab1;
			}
			break;

		case ROOK:
			pbs->pieces[pieceidx].numlegaloffsets = RLOFFSET_MAX;
			pbs->pieces[pieceidx].legaloffsetTab = &R_legaloffsetTab;
			break;

		case KNIGHT:
			pbs->pieces[pieceidx].numlegaloffsets = NLOFFSET_MAX;
			pbs->pieces[pieceidx].legaloffsetTab = &N_legaloffsetTab;
			break;

		case BISHOP:
			pbs->pieces[pieceidx].numlegaloffsets = BLOFFSET_MAX;
			pbs->pieces[pieceidx].legaloffsetTab = &B_legaloffsetTab;
			break;

		case QUEEN:
			pbs->pieces[pieceidx].numlegaloffsets = QLOFFSET_MAX;
			pbs->pieces[pieceidx].legaloffsetTab = &Q_legaloffsetTab;
			break;
		case KING:
			pbs->pieces[pieceidx].numlegaloffsets = KLOFFSET_MAX;
			pbs->pieces[pieceidx].legaloffsetTab = &K_legaloffsetTab;
			break;
		default:
			//printf("unknow piecetype\n");
			break;
	}
	
	return;
}

boardState *createBoard(){
	boardState *pbs;
	int pieceidx = 0;
	int squareidx = 0;
	int playeridx = 0;
	int i;
	pbs = (boardState *)malloc(sizeof(boardState));
	memset(pbs,-1,sizeof(boardState));
	
	playeridx = 0;
	pieceidx = 0;
	squareidx = 0;


/*
-----------------------
0   1  2  3  4  5  6  7
8   9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63
-----------------------
*/
	
	makePiece(pbs,playeridx,pieceidx,squareidx++,ROOK);
	pbs->hasRookMoved[playeridx][pieceidx++] = 0; 
	makePiece(pbs,playeridx,pieceidx++,squareidx++,KNIGHT);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,BISHOP);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,KING);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,QUEEN);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,BISHOP);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,KNIGHT);
	makePiece(pbs,playeridx,pieceidx,squareidx++,ROOK);
	pbs->hasRookMoved[playeridx][pieceidx++] = 0;
	
	pbs->hasKingMoved[playeridx] = 0;

	for(i=0; i < 8; i++)
		makePiece(pbs,playeridx,pieceidx++,squareidx++,PAWN);

	playeridx = 1;
	squareidx = 48;

	for(i=0; i < 8; i++)
		makePiece(pbs,playeridx,pieceidx++,squareidx++,PAWN);

	makePiece(pbs,playeridx,pieceidx,squareidx++,ROOK);
	pbs->hasRookMoved[playeridx][pieceidx++] = 0; 
	makePiece(pbs,playeridx,pieceidx++,squareidx++,KNIGHT);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,BISHOP);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,KING);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,QUEEN);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,BISHOP);
	makePiece(pbs,playeridx,pieceidx++,squareidx++,KNIGHT);
	makePiece(pbs,playeridx,pieceidx,squareidx++,ROOK);
	pbs->hasRookMoved[playeridx][pieceidx++] = 0; 

	pbs->hasKingMoved[playeridx] = 0;


	return pbs;
	
}

void deleteBoard(boardState *pbs){
	if(pbs!=NULL)
		free(pbs);
	pbs= NULL;
	return;
}

/*
White this side
h   g  f  e  d  c  b  a		 
------------------------
0   1  2  3  4  5  6  7 | 1
8   9 10 11 12 13 14 15 | 2
16 17 18 19 20 21 22 23 | 3
24 25 26 27 28 29 30 31 | 4
32 33 34 35 36 37 38 39 | 5
40 41 42 43 44 45 46 47 | 6
48 49 50 51 52 53 54 55 | 7
56 57 58 59 60 61 62 63 | 8
-----------------------
*/

void translateMove(boardState *pbs, moveDesc *pMove,char *notation)
{
	int pieceidx,pieceType,newpos,oldpos;
	char buf[5],letter,number;
	int buf_idx = 0;
	pieceType = pbs->pieces[pMove->pieceidx].piecetype;
	buf[buf_idx++] = pieceNotation[pieceType];
	oldpos = pMove->oldpos;
	newpos = pMove->newpos;
	letter = 'a' + (7-(oldpos%8));
	number = (oldpos/8);
	buf[buf_idx++] = letter;
	buf[buf_idx++] = '1' + number; 
	letter = 'a' + (7-(newpos%8));
	number = (newpos/8);
	buf[buf_idx++] = letter;
	buf[buf_idx++] = '1' + number; 
	memcpy(notation,buf,sizeof(char)*buf_idx);
	return;
}
#if 0
int isvalidpos(int x, int offset){
	int retval=1,newpos;
	newpos = x + offset;
	if(!isbounded(newpos))
		return 0;
	if(ABS(columnlowerbound(x)-columnlowerbound(newpos)) > 2)
		return 0;
	return 1;
}
#endif
	

void addInfluence(boardState *pbs, int pieceidx,int piecepos, int squarepos){
	if(!hasInfluence(pbs,pieceidx,squarepos)){
		pbs->influence_pieceidx[squarepos][pieceidx] = 1;
		pbs->influence_piecepos[squarepos][pieceidx] = piecepos;
		pbs->influence_numpieces[squarepos] += 1;
		pbs->pieces[pieceidx].influence_squarepos[squarepos] = 1;
		pbs->pieces[pieceidx].influence_numsquares ++;
	}
	return;
}

void removeInfluence(boardState *pbs, int pieceidx, int squarepos){
	if(hasInfluence(pbs,pieceidx,squarepos)){
		pbs->influence_pieceidx[squarepos][pieceidx] = 0;
		pbs->influence_pieceidx[squarepos][pieceidx] = 0;
		pbs->influence_numpieces[squarepos] -= 1;	
		pbs->pieces[pieceidx].influence_squarepos[squarepos] = 0;
		pbs->pieces[pieceidx].influence_numsquares --;	
	}
	return;
}
#if 0
void resetInfluence(boardState *pbs, int pieceidx){
	int i;
	memset(pbs->pieces[pieceidx].influence_squarepos,0,sizeof(int)*64);
	pbs->pieces[pieceidx].influence_numsquares = 0;
	for(i=0;i<64;i++){
		if(hasInfluence(pbs,pieceidx,i)){
			pbs->influence_pieceidx[i][pieceidx] = 0;
			pbs->influence_piecepos[i][pieceidx] = -1;
			pbs->influence_numpieces[i] -= 1;
		}
	}
	return;
}
#else
// reset influence of the piece on squares
void resetInfluence(boardState *pbs, int pieceidx){
	int squarepos;
	memset(pbs->pieces[pieceidx].influence_squarepos,0,sizeof(int)*64);
	pbs->pieces[pieceidx].influence_numsquares = 0;
	for(squarepos = 0;squarepos < 64;squarepos++){
		removeInfluence(pbs,pieceidx,squarepos);
	}
	return;
}
#endif


// computes legal moves for  a given piece
void createMoves(boardState *pbs, int pieceidx){
	int i = 0, j, currpos,newpos, k,maxlegal=0,otheridx;
	int numFreeSqaures;
	int *legalMoves = &pbs->pieces[pieceidx].legalMoves[0];
	int *maxLegal = &pbs->pieces[pieceidx].numLegal;
	int prevnewPos,isFriendly;
	
	*maxLegal = 0;

	resetInfluence(pbs,pieceidx);
	
	if(pbs->pieces[pieceidx].computeInteraction)
	{
		numDynAnalysis ++;
		for(i=0;i<32;i++)
		{
			pbs->pieces[pieceidx].enemyAttackedidxflag[i];
			if(pbs->pieces[pieceidx].enemyAttackedidxflag[i] == 1){
				pbs->pieces[i].computeInteraction = 1;
			}
			if(pbs->pieces[pieceidx].enemyAttackingidxflag[i] == 1){
				pbs->pieces[i].computeInteraction = 1;
			}
			if(pbs->pieces[pieceidx].friendDefendedidxflag[i] == 1){
				pbs->pieces[i].computeInteraction = 1;
			}
			if(pbs->pieces[pieceidx].friendDefendingidxflag[i] == 1){
				pbs->pieces[i].computeInteraction = 1;
			}
		}
		pbs->pieces[pieceidx].numAttacked = 0;
		pbs->pieces[pieceidx].numDefended = 0;
		pbs->pieces[pieceidx].numAttacking = 0;
		pbs->pieces[pieceidx].numAttacking = 0;
		memset(pbs->pieces[pieceidx].enemyAttackedidxflag,0,32*sizeof(int));
		memset(pbs->pieces[pieceidx].friendDefendedidxflag,0,32*sizeof(int));
		memset(pbs->pieces[pieceidx].friendDefendingidxflag,0,32*sizeof(int));
		memset(pbs->pieces[pieceidx].enemyAttackingidxflag,0,32*sizeof(int));
		pbs->pieces[pieceidx].computeInteraction = 0;
	}


	
	if(pbs->pieces[pieceidx].isalive)
	{
		pbs->pieces[pieceidx].vpos = 0;
		//pbs->pieces[pieceidx].vdyn = 0;
		switch(pbs->pieces[pieceidx].piecetype)
		{
		
			case PAWN:
			{
				// for bishop, rook and minister
				k = 0;		
				currpos = pbs->pieces[pieceidx].squareidx;
				numFreeSqaures = 0;
				for(j=0;j<pbs->pieces[pieceidx].numlegaloffsets;j++)
				{
					newpos = currpos + pbs->pieces[pieceidx].legaloffsetTab[j];
					if(ABS(pbs->pieces[pieceidx].legaloffsetTab[j])%8 != 0)
					{
						// Capture type approach of a pawn
						if(isvalidpos(currpos,newpos))
						{
							addInfluence(pbs,pieceidx,currpos,newpos);
							if(!isempty(pbs->board[newpos]))
							{
								otheridx = pbs->board[newpos];
								isFriendly = areFriends(pbs,pieceidx,otheridx);
								if(!isFriendly)
								{
									// if its an enemy piece then its valid to capture	
									legalMoves[maxlegal++] = newpos;		
									numFreeSqaures ++;
									
									if(!pbs->pieces[pieceidx].enemyAttackedidxflag[otheridx]){
										pbs->pieces[pieceidx].numAttacked ++;
										pbs->pieces[pieceidx].enemyAttackedidxflag[otheridx] = 1;
										pbs->pieces[pieceidx].enemyAttackedVal[otheridx] = pbs->pieces[otheridx].vint;
									}

									if(!pbs->pieces[otheridx].enemyAttackingidxflag[pieceidx]){
										pbs->pieces[otheridx].numAttacking ++;
										pbs->pieces[otheridx].enemyAttackingidxflag[pieceidx] = 1;									
										pbs->pieces[otheridx].enemyAttackingVal[pieceidx] = pbs->pieces[pieceidx].vint;
									}
								}
								else
								{
									if(!pbs->pieces[pieceidx].friendDefendedidxflag[otheridx]){
										pbs->pieces[pieceidx].numDefended ++;
										pbs->pieces[pieceidx].friendDefendedidxflag[otheridx] = 1;
										pbs->pieces[pieceidx].friendDefendedVal[otheridx] = pbs->pieces[otheridx].vint;
									}
									if(!pbs->pieces[otheridx].friendDefendingidxflag[pieceidx]){
										pbs->pieces[otheridx].numDefending ++;
										pbs->pieces[otheridx].friendDefendingidxflag[pieceidx] = 1;									
										pbs->pieces[otheridx].friendDefendingVal[pieceidx] = pbs->pieces[pieceidx].vint;
									}
								}								
							}						
						}
					}
					else
					{
						
						if(isvalidpos(currpos,newpos))
						{
							addInfluence(pbs,pieceidx,currpos,newpos);
							if((newpos-currpos)==16)
							{
								if(isempty(pbs->board[newpos]) && isempty(pbs->board[newpos-8]))
								{
									legalMoves[maxlegal++] = newpos;
									numFreeSqaures ++;
								}
							}else if((newpos-currpos)==-16)
							{
								if(isempty(pbs->board[newpos]) && isempty(pbs->board[newpos+8]))
								{
									legalMoves[maxlegal++] = newpos;
									numFreeSqaures ++;
								}
							}
							else
							{
								if(isempty(pbs->board[newpos]))
								{
									legalMoves[maxlegal++] = newpos;
									numFreeSqaures ++;
								}							
							}
						}
					}
				}
				
				break;
			}
		
		case KNIGHT:
		case KING:
			{
				// for bishop, rook and minister
				k = 0;		
				currpos = pbs->pieces[pieceidx].squareidx;
				numFreeSqaures = 0;
				for(j=0;j<pbs->pieces[pieceidx].numlegaloffsets;j++)
				{
					newpos = currpos + pbs->pieces[pieceidx].legaloffsetTab[j];
					if(isvalidpos(currpos,newpos))
					{
						addInfluence(pbs,pieceidx,currpos,newpos);
						if(isempty(pbs->board[newpos])){
							legalMoves[maxlegal++] = newpos;
							numFreeSqaures ++;
						}
						else{
							otheridx = pbs->board[newpos];
							isFriendly = areFriends(pbs,pieceidx,otheridx);
							if(!isFriendly)
							{
								// if the other square is not empty and is occupied by an enemy piece,capturing that is a valid move
								legalMoves[maxlegal++] = newpos;
								numFreeSqaures ++;
								if(!pbs->pieces[pieceidx].enemyAttackedidxflag[otheridx]){
									pbs->pieces[pieceidx].numAttacked ++;
									pbs->pieces[pieceidx].enemyAttackedidxflag[otheridx] = 1;
									pbs->pieces[pieceidx].enemyAttackedVal[otheridx] = pbs->pieces[otheridx].vint;
								}
								if(!pbs->pieces[otheridx].enemyAttackingidxflag[pieceidx]){
									pbs->pieces[otheridx].numAttacking ++;
									pbs->pieces[otheridx].enemyAttackingidxflag[pieceidx] = 1;									
									pbs->pieces[otheridx].enemyAttackingVal[pieceidx] = pbs->pieces[pieceidx].vint;
								}

								//pbs->pieces[otheridx].vdyn -= pbs->pieces[otheridx].tot_value; // this piece is under the danger of getting killed => losing its total value
								//pbs->pieces[pieceidx].vdyn -= pbs->pieces[pieceidx].tot_value; // when i kill the other piece i may get killed in return
							}
							else{
								if(!pbs->pieces[pieceidx].friendDefendedidxflag[otheridx]){
									pbs->pieces[pieceidx].numDefended ++;
									pbs->pieces[pieceidx].friendDefendedidxflag[otheridx] = 1;
									pbs->pieces[pieceidx].friendDefendedVal[otheridx] = pbs->pieces[otheridx].vint;
								}
								if(!pbs->pieces[otheridx].friendDefendingidxflag[pieceidx]){
									pbs->pieces[otheridx].numDefending ++;
									pbs->pieces[otheridx].friendDefendingidxflag[pieceidx] = 1;									
									pbs->pieces[otheridx].friendDefendingVal[pieceidx] = pbs->pieces[pieceidx].vint;
								}								
								//pbs->pieces[otheridx].vdyn += intrinsicValue[PAWN]; //pbs->pieces[otheridx].tot_value; // there is some one behind to protect me 
								//pbs->pieces[pieceidx].vdyn -= pbs->pieces[pieceidx].tot_value; // in the worst case , i will be protecting friendly piece with the risk of getting killed myself	
							}							
							//calcDynVal(pbs,pieceidx, currpos,newpos);
						}				
					}
				}
				break;
			}
		default:
			{
				// for bishop, rook and minister
				k = 0;		
				currpos = pbs->pieces[pieceidx].squareidx;
				numFreeSqaures = 0;
				for(j=0;j<pbs->pieces[pieceidx].numlegaloffsets;j++)
				{
					prevnewPos = currpos;
					newpos = currpos + pbs->pieces[pieceidx].legaloffsetTab[j];
					while((isvalidpos(newpos,prevnewPos))&&(isWithinBoard(newpos)) )
					{
						addInfluence(pbs,pieceidx,currpos,newpos);
						if(isempty(pbs->board[newpos])){
							legalMoves[maxlegal++] = newpos;
							numFreeSqaures ++;
						}
						else{
							otheridx = pbs->board[newpos];
							isFriendly = areFriends(pbs,pieceidx,otheridx);
							if(!isFriendly)
							{
								// if the square is not empty and is occupied by enemy piece, capturing that is a valid move
								legalMoves[maxlegal++] = newpos;
								numFreeSqaures ++;
								if(!pbs->pieces[pieceidx].enemyAttackedidxflag[otheridx]){
									pbs->pieces[pieceidx].numAttacked ++;
									pbs->pieces[pieceidx].enemyAttackedidxflag[otheridx] = 1;
									pbs->pieces[pieceidx].enemyAttackedVal[otheridx] = pbs->pieces[otheridx].vint;
								}

								if(!pbs->pieces[otheridx].enemyAttackingidxflag[pieceidx]){
									pbs->pieces[otheridx].numAttacking ++;
									pbs->pieces[otheridx].enemyAttackingidxflag[pieceidx] = 1;									
									pbs->pieces[otheridx].enemyAttackingVal[pieceidx] = pbs->pieces[pieceidx].vint;
								}

								//pbs->pieces[otheridx].vdyn -= pbs->pieces[otheridx].tot_value; // this piece is under the danger of getting killed => losing its total value
								//pbs->pieces[pieceidx].vdyn -= pbs->pieces[pieceidx].tot_value; // when i kill the other piece i may get killed in return
							}
							else
							{
								if(!pbs->pieces[pieceidx].friendDefendedidxflag[otheridx]){
									pbs->pieces[pieceidx].numDefended ++;
									pbs->pieces[pieceidx].friendDefendedidxflag[otheridx] = 1;
									pbs->pieces[pieceidx].friendDefendedVal[otheridx] = pbs->pieces[otheridx].vint;
								}
								if(!pbs->pieces[otheridx].friendDefendingidxflag[pieceidx]){
									pbs->pieces[otheridx].numDefending ++;
									pbs->pieces[otheridx].friendDefendingidxflag[pieceidx] = 1;									
									pbs->pieces[otheridx].friendDefendingVal[pieceidx] = pbs->pieces[pieceidx].vint;
								}
								//pbs->pieces[otheridx].vdyn += intrinsicValue[PAWN]; //pbs->pieces[otheridx].tot_value; // there is some one behind to protect me 
								//pbs->pieces[pieceidx].vdyn -= pbs->pieces[pieceidx].tot_value; // in the worst case , i will be protecting friendly piece with the risk of getting killed myself	
							}
							//calcDynVal(pbs,pieceidx, currpos,newpos);								
							break;
						}
						prevnewPos = newpos;
						newpos += pbs->pieces[pieceidx].legaloffsetTab[j];
					}											
				}
				break;
			}
		}
		calcPosVal(pbs,pieceidx, numFreeSqaures);
		*maxLegal = maxlegal;
	}
	else{
		*maxLegal = 0;
	//	pbs->pieces[pieceidx].vpos = 0;
	}
	//calcTotVal(pbs,pieceidx); // updating total value here will effect the calculation of other nodes
	return;
}



/*
-----------------------
0   1  2  3  4  5  6  7
8   9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63
-----------------------
*/

int movePiece(boardState *pbs, moveDesc *pMove){
	int pieceidx,otherpieceidx ;
	int currPos, newPos,i;
	int pieceidx2,otherpieceidx2 ;
	int currPos2, newPos2;

	currPos = pMove->oldpos;
	newPos = pMove->newpos;
	pieceidx = pMove->pieceidx;

	currPos2 = pMove->oldpos2;
	newPos2 = pMove->newpos2;
	pieceidx2 = pMove->pieceidx2;

	if(!isempty(pbs->board[currPos]))
	{
		if(isempty(pbs->board[newPos]))
		{
			// move the piece , no capture involved;
			pbs->board[currPos] = -1;
			pbs->board[newPos] = pieceidx;
			pbs->pieces[pieceidx].squareidx = newPos;
			if(pbs->pieces[pieceidx].piecetype == PAWN){
				// check if the move is the first special two steps move
				pbs->pieces[pieceidx].numlegaloffsets = PLOFFSET_MAX - 1;// the last two step move will no longer be allowed after moving for the first time
			}
		}
		else
		{
			// move the piece and capture the opponents piece
			otherpieceidx = pbs->board[newPos];
			if(areFriends(pbs,pieceidx,otherpieceidx)){
				//DEBUG_PRINT("Fatal error : how can you capture your own piece\n");
				return -1;
			}
			if(pbs->pieces[pieceidx].piecetype == PAWN){
				// check if the move is the first special two steps move
				pbs->pieces[pieceidx].numlegaloffsets = PLOFFSET_MAX - 1;// the last two step move will no longer be allowed after moving for the first time
			}
			pbs->board[currPos] = -1;
			pbs->board[newPos] = pieceidx;
			pbs->pieces[pieceidx].squareidx = newPos;
			pbs->pieces[otherpieceidx].isalive = FALSE;
			resetInfluence(pbs,otherpieceidx);			

		}	
	}
 
	if(pieceidx2 != -1)
	{
		DEBUG_PRINT("two pieces moving in a same move %d\n",pieceidx2);
		if(!isempty(pbs->board[currPos2]))
		{
			if(isempty(pbs->board[newPos2]))
			{
				// move the piece , no capture involved;
				pbs->board[currPos2] = -1;
				pbs->board[newPos2] = pieceidx2;
				pbs->pieces[pieceidx2].squareidx = newPos2;
				if(pbs->pieces[pieceidx2].piecetype == PAWN){
					// check if the move is the first special two steps move
					pbs->pieces[pieceidx2].numlegaloffsets = PLOFFSET_MAX - 1;// the last two step move will no longer be allowed after moving for the first time
				}
			}
			else
			{
				// move the piece and capture the opponents piece
				otherpieceidx = pbs->board[newPos2];
				if(areFriends(pbs,pieceidx2,otherpieceidx)){
					//DEBUG_PRINT("Fatal error : how can you capture your own piece\n");
					return -1;
				}
				if(pbs->pieces[pieceidx2].piecetype == PAWN){
					// check if the move is the first special two steps move
					pbs->pieces[pieceidx2].numlegaloffsets = PLOFFSET_MAX - 1;// the last two step move will no longer be allowed after moving for the first time
				}
				pbs->board[currPos2] = -1;
				pbs->board[newPos2] = pieceidx2;
				pbs->pieces[pieceidx2].squareidx = newPos2;
				pbs->pieces[otherpieceidx].isalive = FALSE;
				resetInfluence(pbs,otherpieceidx);			

			}	
		}
	}
	return 0;
}


float evalPosition(boardState *pbs){
	// evaluate the board position with respect to player 0 - player 1
	float total_score = 0;
	int i;
	
	for(i=0;i<16;i++){
		if(pbs->pieces[i].isalive){
			calcDynVal(pbs,i);
			calcTotVal(pbs,i);		
			total_score += pbs->pieces[i].tot_value;
		}
	}
	for(i=16;i<32;i++){
		if(pbs->pieces[i].isalive){
			calcDynVal(pbs,i);
			calcTotVal(pbs,i);
			total_score -= pbs->pieces[i].tot_value;
		}
	}
	pbs->total_score = total_score;
	return total_score;
}
int islegal(boardState *pbs, moveDesc *pMove){
	int offset,pieceidx,pieceType,i;
	offset = pMove->newpos - pMove->oldpos;
	pieceidx = pMove->pieceidx;
	for(i=0;i<pbs->pieces[pieceidx].numlegaloffsets;i++){
		if(offset == pbs->pieces[pieceidx].legaloffsetTab[i])
			return 1;
	}
	return 0;
}

#define SEARCH_DEPTH 3

void updateInfluence(boardState *pbs, moveDesc *pMove){
	int pieceidx,otherpieceidx;
	int oldpos, newpos,squarepos;

	int pieceidx2;
	int oldpos2, newpos2,squarepos2;

	
	pieceidx = pMove->pieceidx;
	oldpos = pMove->oldpos;
	newpos = pMove->newpos;

	pieceidx2 = pMove->pieceidx2;
	oldpos2 = pMove->oldpos2;
	newpos2 = pMove->newpos2;


	numDynAnalysis = 0;
	// update legal moves and influence of all the pieces influencing oldpos and newpos 
	// create moves for the moving piece
	pbs->pieces[pieceidx].computeInteraction = 1;
	createMoves(pbs,pieceidx);

	for(otherpieceidx = 0; otherpieceidx < pieceidx; otherpieceidx ++)
	{
		if(isalive(pbs,otherpieceidx)){
			if((hasInfluence(pbs,otherpieceidx,oldpos))||(hasInfluence(pbs,otherpieceidx,newpos))){		
				pbs->pieces[otherpieceidx].computeInteraction = 1;
				createMoves(pbs,otherpieceidx);				
			//calcTotVal(pbs,otherpieceidx);
			}
		}
	}
	
	for(otherpieceidx = pieceidx+1; otherpieceidx < 32; otherpieceidx ++)
	{
		if(isalive(pbs,otherpieceidx)){
			if((hasInfluence(pbs,otherpieceidx,oldpos))||(hasInfluence(pbs,otherpieceidx,newpos))){
				pbs->pieces[otherpieceidx].computeInteraction = 1;
				createMoves(pbs,otherpieceidx);
			//calcTotVal(otherpieceidx);
			}
		}
	}
	//DEBUG_PRINT("num of pieces with dynamic update %d \n",numDynAnalysis);
	if(pieceidx2!=-1)
	{
		
		for(otherpieceidx = 0; otherpieceidx < pieceidx2; otherpieceidx ++)
		{
			if(isalive(pbs,otherpieceidx)){
				if((hasInfluence(pbs,otherpieceidx,oldpos))||(hasInfluence(pbs,otherpieceidx,newpos))){		
					pbs->pieces[otherpieceidx].computeInteraction = 1;
					createMoves(pbs,otherpieceidx);				
					//calcTotVal(pbs,otherpieceidx);
				}
			}
		}
		
		for(otherpieceidx = pieceidx2+1; otherpieceidx < 32; otherpieceidx ++)
		{
			if(isalive(pbs,otherpieceidx)){
				if((hasInfluence(pbs,otherpieceidx,oldpos))||(hasInfluence(pbs,otherpieceidx,newpos))){
					pbs->pieces[otherpieceidx].computeInteraction = 1;
					createMoves(pbs,otherpieceidx);
					//calcTotVal(otherpieceidx);
				}
			}
		}			
	}

	return;
}

void initBoard(boardState *pbs){
	int pieceidx;
	for(pieceidx = 0; pieceidx <32;pieceidx++){
		pbs->pieces[pieceidx].computeInteraction = 1;
		createMoves(pbs,pieceidx);	
	}	
	evalPosition(pbs);
	for(pieceidx = 0;pieceidx < 32; pieceidx ++){
		pbs->pieces[pieceidx].computeInteraction = 0;
	}
	return;
}

void executeMove(boardState *pbs, moveDesc *pMove){
	int pieceidx;
	numDynAnalysis = 0;
	if(pMove->pieceidx!=-1){
		movePiece(pbs,pMove);
		updateInfluence(pbs,pMove);
		
	}
#if 0
	for(pieceidx = 0; pieceidx < 32;pieceidx ++){
		calcTotVal(pbs,pieceidx);
#endif
#if 0
	for(pieceidx = 0; pieceidx < 32;pieceidx ++){
		
		createMoves(pbs,pieceidx);		
	}
#endif
	return;
}
extern FILE *fdebug;
void genMove(void *playerhandle, boardState *pbs, moveDesc *pMove);
#define PLYDEPTH 3
extern int playerid_of_computer;
extern int movenow;
extern int resetboard_flag;

//params InitParams;
void setDefaultParams(params *pInitParams){
	pInitParams->a1 = 0.2;
	pInitParams->a2 = 0.2;
	pInitParams->bishop_val = intrinsicValue[BISHOP];
	pInitParams->king_val = intrinsicValue[KING];
	pInitParams->knight_val = intrinsicValue[KNIGHT];
	pInitParams->pawn_val = intrinsicValue[PAWN];
	pInitParams->queen_val = intrinsicValue[QUEEN];
	pInitParams->rook_val = intrinsicValue[ROOK];
	pInitParams->wdyn = 1;
	pInitParams->wint = 1;
	pInitParams->wpos = 1;
	return;
}
void readParams(params *pInitParams, FILE *fini){
#if 1	
	fscanf(fini,"%f\n",&pInitParams->a1);
	fscanf(fini,"%f\n",&pInitParams->a2);
	fscanf(fini,"%f\n",&pInitParams->pawn_val);
	fscanf(fini,"%f\n",&pInitParams->knight_val);
	fscanf(fini,"%f\n",&pInitParams->bishop_val);
	fscanf(fini,"%f\n",&pInitParams->rook_val);
	fscanf(fini,"%f\n",&pInitParams->queen_val);
	fscanf(fini,"%f\n",&pInitParams->king_val);
	fscanf(fini,"%f\n",&pInitParams->wint);
	fscanf(fini,"%f\n",&pInitParams->wdyn);
	fscanf(fini,"%f\n",&pInitParams->wpos);
#else
	fread(&pInitParams->a1,1,sizeof(float),fini);
	fread(&pInitParams->a2,1,sizeof(float),fini);
	fread(&pInitParams->pawn_val,1,sizeof(float),fini);
	fread(&pInitParams->knight_val,1,sizeof(float),fini);
	fread(&pInitParams->bishop_val,1,sizeof(float),fini);
	fread(&pInitParams->rook_val,1,sizeof(float),fini);
	fread(&pInitParams->queen_val,1,sizeof(float),fini);
	fread(&pInitParams->king_val,1,sizeof(float),fini);
	fread(&pInitParams->wint,1,sizeof(float),fini);
	fread(&pInitParams->wdyn,1,sizeof(float),fini);
	fread(&pInitParams->wpos,1,sizeof(float),fini);
#endif
	return;
}
void writeParams(params *pInitParams,FILE *fini){
#if 1
	fprintf(fini,"%f\n",pInitParams->a1);
	fprintf(fini,"%f\n",pInitParams->a2);
	fprintf(fini,"%f\n",pInitParams->pawn_val);
	fprintf(fini,"%f\n",pInitParams->knight_val);
	fprintf(fini,"%f\n",pInitParams->bishop_val);
	fprintf(fini,"%f\n",pInitParams->rook_val);
	fprintf(fini,"%f\n",pInitParams->queen_val);
	fprintf(fini,"%f\n",pInitParams->king_val);
	fprintf(fini,"%f\n",pInitParams->wint);
	fprintf(fini,"%f\n",pInitParams->wdyn);
	fprintf(fini,"%f\n",pInitParams->wpos);
#else
	fwrite(&pInitParams->a1,1,sizeof(float),fini);
	fwrite(&pInitParams->a2,1,sizeof(float),fini);
	fwrite(&pInitParams->pawn_val,1,sizeof(float),fini);
	fwrite(&pInitParams->knight_val,1,sizeof(float),fini);
	fwrite(&pInitParams->bishop_val,1,sizeof(float),fini);
	fwrite(&pInitParams->rook_val,1,sizeof(float),fini);
	fwrite(&pInitParams->queen_val,1,sizeof(float),fini);
	fwrite(&pInitParams->king_val,1,sizeof(float),fini);
	fwrite(&pInitParams->wint,1,sizeof(float),fini);
	fwrite(&pInitParams->wdyn,1,sizeof(float),fini);
	fwrite(&pInitParams->wpos,1,sizeof(float),fini);
#endif
	intrinsicValue[PAWN] = pInitParams->pawn_val;
	intrinsicValue[KNIGHT] = pInitParams->knight_val;
	intrinsicValue[BISHOP] = pInitParams->bishop_val;
	intrinsicValue[ROOK] = pInitParams->rook_val;
	intrinsicValue[QUEEN] = pInitParams->queen_val;
	intrinsicValue[KING] = pInitParams->king_val;
	return;
}
main()
{
	boardState *pbs;
	int legalMoves[100], maxLegal=0;
	int valid,i;
	void *player0,*player1;
	int retVal;
	moveDesc move;
	char movestring[6];
	FILE *fmoves;
	int numMoves = 0;
	moveDesc FirstMove[5];
	char *filename;
	char constname[]="moves_";
	char msg[2000];
	int isMove;
#if 1
	FILE *iniFile;
	iniFile = fopen("alphaBeta.ini","r");
	if(iniFile==NULL){
		// no ini file... create one with default param settings
		setDefaultParams(&InitParams);
		iniFile = fopen("alphaBeta.ini","w");
		writeParams(&InitParams,iniFile);
		fclose(iniFile);
	}
	else{
		// load params from ini file
		readParams(&InitParams, iniFile);
		fclose(iniFile);
	}
#endif

	DEBUG_INIT("enginedebug.txt");
	DEBUG_PRINT("---- Start of debug info ---\n");

	movestring[5] = '\0';
	//fmoves = fopen("moves.pgn","w");
	//fdebug = fopen("commands.txt","w");
	DEBUG_PRINT("Creating board...");
	pbs = createBoard();
	DEBUG_PRINT("done\n");
	//playerid_of_computer = 1;
	//movenow = 0;
	DEBUG_PRINT("Creating players...");
	player0 = createPlayer(0);
	player1 = createPlayer(1);
	DEBUG_PRINT("Done\n");

	DEBUG_PRINT("Initialize board..");
	initBoard(pbs);
	DEBUG_PRINT("Done\n");
/*
-----------------------
R   N  B  K  Q  B  N  R
0   1  2  3  4  5  6  7
8   9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63
-----------------------
*/
	playerid_of_computer = 1;
	movenow = 0;
	
	while(1)
	{
		//DEBUG_PRINT("movenow %d resetboard %d\n",movenow,resetboard_flag);
		if(movenow == 0){	
			getMessage(msg);
			//DEBUG_PRINT(msg);
			//DEBUG_PRINT("\n");
			isMove = handleMessage(msg);
			//DEBUG_PRINT("ismove %d\n",isMove);
		}
		//if(isMove)
		if(resetboard_flag == 1){
			deleteBoard(pbs);
			pbs = createBoard();
			initBoard(pbs);	
			resetboard_flag = 0;
		}
		if(1)
		{
	//		fprintf(fdebug,"plyerid %d movenow %d\n",playerid_of_computer,movenow);
			if(playerid_of_computer == 1)
			{
				valid = parseMoveFromMsg(pbs,msg,&move);
				if(valid && movenow == 0) 
				{
					//fprintf(fdebug,"processing move oldpos %d newpos %d pieceidx %d\n",move.oldpos,move.newpos,move.pieceidx);			
					executeMove(pbs,&move);			
					movenow = 1;
				}else if(movenow == 1)
				{
					genMove(player1,pbs,&move); 
					//fprintf(fdebug,"Generated move oldpos %d newpos %d pieceidx %d\n",move.oldpos,move.newpos,move.pieceidx);
					sendMove(&move);
					executeMove(pbs,&move);
				//		translateMove(pbs,&move,movestring);
				//		fprintf(fmoves,"%d)%s",numMoves + 1, movestring);
				//		printf("%d)%s",numMoves + 1, movestring);
					numMoves ++;
					movenow = 0;
				}				
			}
			else if(playerid_of_computer == 0)
			{
				if(movenow == 0){
				//	getMessage(msg);
				//	isMove = handleMessage(msg);
					valid = parseMoveFromMsg(pbs,msg,&move);
					if(valid){
					  executeMove(pbs,&move);				
					  movenow = 1;
					}
				}else if(movenow == 1)
				{
					genMove(player0,pbs,&move); 
					//fprintf(fdebug,"Generated move oldpos %d newpos %d pieceidx %d\n",move.oldpos,move.newpos,move.pieceidx);
					sendMove(&move);
					executeMove(pbs,&move);
					movenow = 0;
				}
			}
			
		}
		
	}
	deleteBoard(pbs);
//	createMoves(pbs,25,legalMoves,&maxLegal);
//	movePiece(pbs,1,18);	
	//fclose(fmoves);

}
#define INFINITY 12345678990

int GameOver(boardState *pbs){
	int pieceidx;
	for(pieceidx =0; pieceidx < 32; pieceidx ++){
		if(!pbs->pieces[pieceidx].isalive){
			if(pbs->pieces[pieceidx].piecetype == KING)
				return 1;		
		}
	}
	return 0;
}

int RedValue(boardState *pbs, moveDesc *pMove, float alpha, float beta,int depth) ;
int BlueValue(boardState *pbs, moveDesc *pMove, float alpha, float beta,int depth) ;

int BlueValue(boardState *pbs, moveDesc *pMove, float alpha, float beta,int depth) 
{
	float x,max = -INFINITY;
	moveDesc localMove,othermove,maxmove,alphamove;
	int pieceidx = 0;
	int legalmoveidx = 0;
	boardState tempboardState;	
	if ((GameOver(pbs))|| (depth>PLYDEPTH))
        return evalPosition(pbs);
	
	localMove.pieceidx2 = othermove.pieceidx2 = maxmove.pieceidx2 = alphamove.pieceidx2 = -1;
    
    //for each legal move m in board b 
	for(pieceidx = 0;pieceidx < 16;pieceidx ++)
	{
		if(pbs->pieces[pieceidx].isalive)
		{
			localMove.pieceidx = pieceidx;
			localMove.validate = 0;
			for(legalmoveidx = 0;legalmoveidx < pbs->pieces[pieceidx].numLegal;legalmoveidx++)
			{
			    memcpy(&tempboardState,pbs,sizeof(boardState));
				localMove.newpos = pbs->pieces[pieceidx].legalMoves[legalmoveidx];
				localMove.oldpos = pbs->pieces[pieceidx].squareidx;
				executeMove(&tempboardState,&localMove);			
				x = RedValue(&tempboardState,&othermove,alpha,beta,depth+1);
				if(x > max){
					memcpy(&maxmove,&localMove,sizeof(moveDesc));				
					max = x;
				}
				if(x > alpha) {
					memcpy(&alphamove,&localMove,sizeof(moveDesc));				
					alpha = x;				
				}
				if(alpha >= beta ) {
					memcpy(pMove,&alphamove,sizeof(moveDesc));
					return alpha;
				}			
			}
		}
	}
	memcpy(pMove,&maxmove,sizeof(moveDesc));    
	return max;
}


int RedValue(boardState *pbs, moveDesc *pMove, float alpha, float beta, int depth) 
{
	float x,min = INFINITY;
	moveDesc localMove,othermove,minmove,betamove;
	int pieceidx = 0;
	int legalmoveidx = 0;
	//	boardState cbState;
	boardState tempboardState;
	if ((GameOver(pbs))|| (depth>PLYDEPTH))
        return evalPosition(pbs);

	localMove.pieceidx2 = othermove.pieceidx2 = minmove.pieceidx2 = betamove.pieceidx2 = -1;
    
    //for each legal move m in board b 
	for(pieceidx = 31;pieceidx >= 16;pieceidx --)
	{
		if(pbs->pieces[pieceidx].isalive)
		{
			localMove.pieceidx = pieceidx;
			localMove.validate = 0;
			for(legalmoveidx = 0;legalmoveidx < pbs->pieces[pieceidx].numLegal;legalmoveidx++)
			{
			    memcpy(&tempboardState,pbs,sizeof(boardState));
				localMove.newpos = pbs->pieces[pieceidx].legalMoves[legalmoveidx];
				localMove.oldpos = pbs->pieces[pieceidx].squareidx;
				executeMove(&tempboardState,&localMove);			
				x = BlueValue(&tempboardState,&othermove,alpha,beta,depth+1);
				if(x < min){
					memcpy(&minmove,&localMove,sizeof(moveDesc));				
					min = x;
				}
				if(x < beta) {
					memcpy(&betamove,&localMove,sizeof(moveDesc));				
					beta = x;				
				}
				if(alpha >= beta ) {
					memcpy(pMove,&betamove,sizeof(moveDesc));
					return beta;
				}			
			}
		}
	}
	memcpy(pMove,&minmove,sizeof(moveDesc));    
	return min;
}

void alphaBetaSearch(int playeridx, boardState *pbs, moveDesc *pMove, float alpha, float beta,int depth)
{
	if(playeridx == 0)
	
		BlueValue(pbs,pMove,alpha,beta,0);
	
	else
	
		RedValue(pbs,pMove,alpha,beta,0);
	
	return;
}

// generate move and store it in pMove 
void genMove(void *player, boardState *pbs, moveDesc *pMove)
{
	playerObj *p = (playerObj *)player;
	float alpha, beta,x;
	
	alpha = -INFINITY;
	beta = INFINITY;
	alphaBetaSearch(p->playerid,pbs,pMove,alpha, beta, 0);
	
	return;
}



	
	



































